#ifndef _ML_DATA_VECTOR_H_
#define _ML_DATA_VECTOR_H_
#include "MLCommon.h"
#include "MLTools.h"
_MYLABLIB_BEGIN


// Data Vector
template<typename ElemType>
class CMLDataVector
{
public:
	// Constructor and Destructor
	CMLDataVector(){};
	CMLDataVector(int nSize)
	{
		m_vElements.resize((size_t)nSize);
	}
	CMLDataVector(const CMLDataVector<ElemType>& src)
	{
		operator=(src);
	}
	~CMLDataVector(){};

public:
	// Methods
	inline int size() const { return (int)m_vElements.size(); };

	inline void resize(int nSize) { m_vElements.resize((size_t)nSize); };
	
	inline void zero();

	inline void setid(int id) { m_nId = id; };

	inline int id() { return m_nId; };
	
	inline CMLDataVector<ElemType>& operator=(const CMLDataVector<ElemType>& src)
	{
		m_vElements = src.m_vElements;
		m_nId = src.m_nId;
		return *this;
	}

	inline const ElemType& operator[](int nPos) const { return m_vElements[nPos]; };
	
	inline ElemType& operator[](int nPos) { return m_vElements[nPos]; };

	inline ElemType Norm1(void) const
	{
		ElemType sum = (ElemType)0;
		int i;
		for (i=0; i<(int)m_vElements.size(); i++)
			sum += m_vElements[i];
		return sum;
	}

	inline ElemType Norm2(void) const
	{
		ElemType sum = (ElemType)0;
		int i;
		for (i=0; i<(int)m_vElements.size(); i++)
			sum += m_vElements[i]*m_vElements[i];
		return (ElemType)sqrt(sum);
	}
	
	inline CMLDataVector<ElemType>& add(const CMLDataVector<ElemType>& src)
	{
		int i;
		if (size() == 0)
			return operator=(src);

		for (i=0; i<size(); i++)
			m_vElements[i] += src.m_vElements[i];
		return *this;
	}

	inline CMLDataVector<ElemType>& sub(const CMLDataVector<ElemType>& src)
	{
		int i;
		for (i=0; i<size(); i++)
			m_vElements[i] -= src.m_vElements[i];
		return *this;
	}

	inline CMLDataVector<ElemType>& mul(ElemType val)
	{
		int i;
		for (i=0; i<size(); i++)
			m_vElements[i] *= val;
		return *this;
	}

	inline CMLDataVector<ElemType>& div(ElemType val)
	{
		int i;
		for (i=0; i<size(); i++)
			m_vElements[i] /= val;
		return *this;
	}

	inline CMLDataVector<ElemType>& square()
	{
		int i;
		for (i=0; i<size(); i++)
			m_vElements[i] *= m_vElements[i];
		return *this;
	}

	inline CMLDataVector<ElemType>& pow(double dPow)
	{
		int i;
		for (i=0; i<size(); i++)
			m_vElements[i] = ::pow(m_vElements[i], dPow);
		return *this;
	}

	inline CMLDataVector<ElemType>& dotMul(CMLDataVector<ElemType>& v1)
	{
		int i;
		for (i=0; i<size(); i++)
			m_vElements[i] *= v1.m_vElements[i];
		return *this;
	}

	inline CMLDataVector<ElemType>& dotDiv(CMLDataVector<ElemType>& v1)
	{
		int i; 
		for (i=0; i<size(); i++)
			m_vElements[i] /= v1.m_vElements[i];
		return *this;
	}

	inline CMLDataVector<ElemType> split(int pos, int size)
	{
		int i;
		CMLDataVector<ElemType> splice(size);
		for (i=pos; i<size; i++)
			splice[i-pos] = m_vElements[i];
		return splice;
	}

	inline std::wstring ToWString() const
	{
		return ToWString(L',');
	}

	inline std::wstring ToWString(wchar_t sparator) const
	{
		std::wstringstream tempStream;
		int i;
		for (i=0; i<size(); i++)
		{
			tempStream << m_vElements[i];
			if (i != size() -1)
				tempStream << sparator;
		}
		return tempStream.str();
	}

	inline void FromWString(const std::wstring& wstr);

private:
	// Fields
	std::vector<ElemType> m_vElements;
	int m_nId;
};

template<>
inline void CMLDataVector<int>::zero()
{
	int i;
	for (i=0; i<size(); i++)
		m_vElements[i] = 0;
}

template<>
inline void CMLDataVector<double>::zero()
{
	int i;
	for (i=0; i<size(); i++)
		m_vElements[i] = 0.0;
}

template<>
inline void CMLDataVector<int>::FromWString(const std::wstring& wstr)
{
	int i;
	std::vector<std::wstring> vDataPoints;
	CMLTools::SplitString(wstr, vDataPoints);
	resize((int)vDataPoints.size());
	for (i=0; i<size(); i++)
	{
		m_vElements[i] = _wtoi(vDataPoints[i].c_str());
	}
}

template<>
inline void CMLDataVector<double>::FromWString(const std::wstring& wstr)
{
	CMLTools::SplitString(wstr, m_vElements);
}

template<class ElemType>
inline CMLDataVector<ElemType> operator+(const CMLDataVector<ElemType>& v1, const CMLDataVector<ElemType>& v2)
{
	CMLDataVector<ElemType> temp = v1;
	temp.add(v2);
	return temp;
}

template<class ElemType>
inline CMLDataVector<ElemType> operator-(const CMLDataVector<ElemType>& v1, const CMLDataVector<ElemType>& v2)
{
	CMLDataVector<ElemType> temp = v1;
	temp.sub(v2);
	return temp;
}

template<class ElemType>
inline CMLDataVector<ElemType> operator*(const CMLDataVector<ElemType>& v1, double factor)
{
	CMLDataVector<ElemType> temp = v1;
	temp.mul(factor);
	return temp;
}

template<class ElemType>
inline CMLDataVector<ElemType> operator/(const CMLDataVector<ElemType>& v1, double factor)
{
	CMLDataVector<ElemType> temp = v1;
	temp.div(factor);
	return temp;
}

template<class ElemType>
inline CMLDataVector<ElemType> operator^(const CMLDataVector<ElemType>& v1, double dPow)
{
	CMLDataVector<ElemType> temp = v1;
	temp.pow(dPow);
	return temp;
}

template<class ElemType>
inline bool operator<(const CMLDataVector<ElemType>& v1, const CMLDataVector<ElemType>& v2)
{
	int i;
	for (i=0; i<v1.size(); i++)
	{
		if (v1[i] < v2[i])
			return true;
		else if (v1[i] > v2[i])
			return false;
	}
	return false; // equal
}

template<typename ElemType>
inline bool operator==(const CMLDataVector<ElemType>& v1, const CMLDataVector<ElemType>& v2)
{
	if (v1.size() != v2.size())
		return false;
	int i;
	for (i=0; i<v1.size(); i++)
	{
		if (v1[i] != v2[i])
			return false;
	}
	return true;
}

template<typename ElemType>
inline bool operator!=(const CMLDataVector<ElemType>& v1, const CMLDataVector<ElemType>& v2)
{
	return !operator==(v1,v2);
}


_MYLABLIB_END
#endif
